#ifndef __DATABASE_SQLITE_H__
#define __DATABASE_SQLITE_H__

#include <string>
#include <vector>

#include "database.h"
#include "sqlite3.h"

#include "unit.h"
#include "subunit.h"
#include "item.h"
#include "image.h"

namespace verema
{

/**
 * \brief Databse interface implementation to sqlite3 backend
 *
 * This class handles all interactions between the frontend and the database backend. In this case
 * the sqlite3 database.
 */
class Database_Sqlite : public Database
{
private:
	sqlite3 *_db;
	bool _isOpen;

	void connect(std::string dbname_);
	void disconnect();

	void begin_transaction();
	void end_transaction();

	std::string createPositionString(Item &item);
	void positionStringToItem(Item &item, const std::string &positionString);

public:
	/**
	 * \brief Constructor to establish a connection to the Database
	 *
	 * This constructor initializes the database connection. The database file dbname
	 * will be used by this object.
	 *
	 * \param dbname name of database file
	 */
	Database_Sqlite(std::string dbname);

    void createNewDatabase(std::string newDbName);
    void openNewDatabase(std::string dbname);

	/**
	 * \brief get a single verema::Unit form the database
	 *
	 * A single verema::Unit will be returned. If the id could not be found in the database
	 * a verema::Unit with its id set to -1 will be returned
	 *
	 * \param id id of verema::Unit to get from database
	 * \return verema::Unit result of the sql statement
	 */
	Unit getUnit(int id);

	/**
	 * \brief put a single verema::Unit into the database
	 *
	 * A single verema::Unit will be put into the database. If the id of the unit is -1 an insert will be
	 * performed. If the id of the unit is greater than 0 an update statement will be performed
	 *
	 * \param &unit the unit to be put into the database
	 * \return the id of the unit will be returned. If a new unit was put into the database the new id
	 * will be returned
	 */
	int putUnit(Unit &unit);

	/**
	 * \brief get all verema::Unit's form the database
	 *
	 * The unit_vector will be cleared and then filled with the verema::Unit's retrieved from
	 * the database. If there are no verema::Unit's retrieved the unit_vector will be empty
	 *
	 * \param unit_vector the std::vector which will be filled
	 */
	void getAllUnits(std::vector<Unit> &unit_vector);

	/**
	 * \brief put vector of verema::Unit's into the database
	 *
	 * All verema::Unit's will be put into the database. If the id of the unit is -1 an insert will be
	 * performed. If the id of the unit is greater than 0 an update statement will be performed
	 *
	 * \param &unit_vector the unit vector to be put into the database
	 * will be returned
	 */
	void putAllUnits(std::vector<Unit> &unit_vector);

	/**
	 * \brief delete a verema::Unit from the database
	 *
	 * A single verema::Unit will be deleted from the database with the supplied id. In addition
	 * to that all verema::Subunits's linked to this verema::Unit will be deleted too.
	 *
	 * \param id the id of the verema::Unit to be deleted
	 */
	void deleteUnit(int id);

	/**
	 * \brief get a single verema::Subunit form the database
	 *
	 * A single verema::Subunit will be returned. If the id could not be found in the database
	 * a \p verema::Unit with its id set to -1 will be returned
	 *
	 * \param id id of verema::Subunit to get from database
	 * \return verema::Subunit result of the sql statement
	 */
	Subunit getSubunit(int id);

	/**
	 * \brief put a single verema::Subunit into the database
	 *
	 * A single verema::Subunit will be put into the database. If the id of the \p subunit is -1 an
	 * insert will be performed. If the id of the subunit is greater than 0 an update statement will
	 * be performed
	 *
	 * \param subunit the subunit to be put into the database
	 * \return the id of the subunit will be returned. If a new subunit was put into the database the
	 * new id will be returned
	 */
	int putSubunit(Subunit &subunit);

	/**
	 * \brief get all verema::Subunit's form the database for a specific verema::Unit
	 *
	 * The subunit_vector will be cleared and then filled with the verema::Subunit's retrieved from
	 * the database which are connected to the verema::Unit with the id supplied in subunit_id.
	 * If there are no verema::Subunit's retrieved the subunit_vector will be empty
	 *
	 * \param &subunit_vector the std::vector which will be filled
	 * \param unit_id only subunits with the \p unit_id will be selected
	 */
	void getAllSubunits(std::vector<Subunit> &subunit_vector, int unit_id);

	/**
	 * \brief put vector of verema::Subunit's into the database
	 *
	 * All verema::Subunit's will be put into the database. If the id of the sub_unit is -1 an insert will be
	 * performed. If the id of the sub_unit is greater than 0 an update statement will be performed
	 *
	 * \param &subunit_vector the unit vector to be put into the database
	 * will be returned
	 */
	void putAllSubunits(std::vector<Subunit> &subunit_vector);

	/**
	 * \brief delete a verema::Subunit from the database
	 *
	 * A single verema::Subunit will be deleted from the database with the supplied id. In addition
	 * to that all verema::Item's linked to this verema::Subunit will be deleted too.
	 *
	 * \param id the id of the verema::Subunit to be deleted
	 */
	void deleteSubunit(int id);

	/**
	 * \brief get a single verema::Item form the database
	 *
	 * A single verema::Item will be returned. If the id could not be found in the database
	 * a verema::Item with its id set to -1 will be returned
	 *
	 * \param id id of verema::Item to get from database
	 * \return verema::Item result of the sql statement
	 */
	Item getItem(int id);

	/**
	 * \brief put a single verema::Item into the database
	 *
	 * A single verema::Item will be put into the database. If the id of the item is -1 an
	 * insert will be performed. If the id of the item is greater than 0 an update statement will
	 * be performed
	 *
	 * \param item the Item to be put into the database
	 * \return the id of the item will be returned. If a new item was put into the database the
	 * new id will be returned
	 */
	int putItem(Item &item);

	/**
	 * \brief get all verema::Item's form the database for a specific verema::Subunit
	 *
	 * The item_vector will be cleared and then filled with the verema::Item's retrieved from
	 * the database which are connected to the verema::Subunit with the id supplied in subunit_id.
	 * If there are no verema::Item's retrieved the item_vector will be empty
	 *
	 * \param item_vector the std::vector which will be filled
	 * \param subunit_id only items with the \p subunit_id will be selected
	 */
	void getAllItems(std::vector<Item> &item_vector, int subunit_id);

	/**
	 * \brief get all verema::Item's form the database for a specific verema::Subunit
	 *
	 * The item_vector will be cleared and then filled with the verema::Item's retrieved from
	 * the database which are connected to the verema::Subunit with the id supplied in subunit_id.
	 * If there are no verema::Item's retrieved the item_vector will be empty.
	 * In addition to that, only those item's will be selected that are used or not used depending
	 * on the paramater \p used
	 *
	 * \param item_vector the std::vector which will be filled
	 * \param subunit_id only items with the \p subunit_id will be selected
	 * \param used only the items with the same used state are selected
	 */
	void getAllItems(std::vector<Item> &item_vector, int subunit_id, bool used);

	/**
	 * \brief put vector of verema::Item's into the database
	 *
	 * All verema::Item's will be put into the database. If the id of the item is -1 an insert will be
	 * performed. If the id of the item is greater than 0 an update statement will be performed
	 *
	 * \param &item_vector the unit vector to be put into the database
	 * will be returned
	 */
	void putAllItems(std::vector<Item> &item_vector);

	/**
	 * \brief delete a verema::Item from the database
	 *
	 * A single verema::Item will be deleted from the database with the supplied id.
	 *
	 * \param id the id of the verema::Item to be deleted
	 */
	void deleteItem(int id);

	/**
	 * \brief get a single verema::Image form the database
	 *
	 * A single verema::Image will be returned. If the id could not be found in the database
	 * a verema::Image with its id set to -1 will be returned
	 *
	 * \param id id of verema::Image to get from database
	 * \return verema::Image result of the sql statement
	 */
	Image getImage(int id);

	/**
	 * \brief put a single verema::Image into the database
	 *
	 * A single verema::Image will be put into the database. If the id of the image is -1 an
	 * insert will be performed. If the id of the image is greater than 0 an update statement will
	 * be performed
	 *
	 * \param image the Image to be put into the database
	 * \return the id of the image will be returned. If a new image was put into the database the
	 * new id will be returned
	 */
    int putImage(Image &image);

	/**
	 * \brief delete a verema::Image from the database
	 *
	 * A single verema::Image will be deleted from the database with the supplied id. In addition
	 * to that all verema::Subunit's linked to this verema::Image will be checked and their
	 * image_id will be set set to -1, indicating that there is no verema::Image connected to
	 * them
	 *
	 * \param id the id of the verema::Image to be deleted
	 */
	void deleteImage(int id);

	~Database_Sqlite();
};

} // namespace verema

#endif // __DATABASE_SQLITE_H__
